﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using SLSearchNavSync.HelperClasses;
using SLSearchNavSync.TimerJobs;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.WebControls;

namespace SLSearchNavSync.ADMIN.SLSearchNavSync
{
    public partial class SearchNavTimerJobSettings : LayoutsPageBase
    {
        public string TimerJobSettingsLabel = "";
        private SPWebApplication _currentWebApp;

        /// <summary>
        /// Page load event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_Load(object sender, EventArgs e)
        {
            TimerJobSettingsLabel = Definitions.SearchNavigationSyncTimerJobTitle + " Settings";
        }


        /// <summary>
        /// Handles extra pre render requirements, registers client id's of form elements for use in JavaScript
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            try
            {
                // Check if the script is already registered, this is necessary because the webpart can be 
                // added multiple times to the same page 
                if (!Page.ClientScript.IsClientScriptBlockRegistered("FormFields"))
                {
                    var formFields = string.Format("var syncAllSiteCollectionsCbId = '{0}';", cbSyncAllSiteCollections.ClientID);

                    Page.ClientScript.RegisterClientScriptBlock(GetType(), "FormFields", formFields, true);
                }
            }
            catch (Exception ex)
            {
                //log to ULS
                UlsHelper.WriteUlsEntry(ex, Microsoft.SharePoint.Administration.TraceSeverity.Unexpected, "",
                                           Definitions.UlsCategory);
            }
        }

        /// <summary>
        /// OnChange event handler for the web application selector
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void WebApplicationSelectorControl_OnContextChange(object sender, EventArgs e)
        {
            try
            {
                _currentWebApp = WebApplicationSelectorControl.CurrentItem;

                //get the timer job settings - load the settings into the form
                var allJobs = GetTimerJobsByName(Definitions.SearchNavigationSyncTimerJobName, _currentWebApp);
                if (allJobs == null)
                {
                    const string errorMessage = "No Timer Jobs exist for the selected Web Application.  You must activate the Softlanding SharePoint 2013 Search Navigation Sync Timer Job Feature first!";
                    OutputMessageToUser(errorMessage, System.Drawing.Color.Red);
                    return;
                }

                foreach (var job in allJobs)
                {
                    if (job is SearchNavigationSyncTimerJobDefinition)
                    {
                        var searchNavSyncJob = job as SearchNavigationSyncTimerJobDefinition;

                        if (!String.IsNullOrEmpty(searchNavSyncJob.SearchCenterUrl))
                        {
                            tbSearchSiteUrl.Text = searchNavSyncJob.SearchCenterUrl;
                            tbSiteCollectionsUrls.Text =
                                ConvertUrlsArrayListToString(searchNavSyncJob.SiteCollectionsUrls);
                            tbSitesToExcludeUrls.Text = ConvertUrlsArrayListToString(searchNavSyncJob.ExcludedSiteUrls);
                            cbAddThisSite.Checked = searchNavSyncJob.AddThisSite;
                            cbThisSiteFirst.Checked = searchNavSyncJob.MakeThisSiteFirst;
                            cbSyncAllSiteCollections.Checked = searchNavSyncJob.SynchronizeAllSiteCollections;

                            break;
                        }
                    }
                }

                OutputMessageToUser(
                    "Click 'Apply' to save your changes to the Search Navigation Synchronization Timer Job",
                    System.Drawing.Color.Gray);
            }
            catch (Exception ex)
            {
                var errorMessage =
                    String.Format(
                        "An error occurred while loading the {0} Timer Job settings.  Please Try Again.<br/><br/>Error: {1}",
                        Definitions.SearchNavigationSyncTimerJobTitle, ex.Message);

                //log error and notify the end user
                UlsHelper.WriteUlsEntry(ex, TraceSeverity.Unexpected, EventSeverity.Error, Definitions.UlsCategory);
                OutputMessageToUser(errorMessage, System.Drawing.Color.Red);
            }
        }

        /// <summary>
        /// Event handler for the Apply button click event
        /// </summary>
        /// <param name="sender">Event Sender</param>
        /// <param name="e">Event Arguements</param>
        protected void BtnApply_Click(object sender, EventArgs e)
        {
            try
            {
                _currentWebApp = WebApplicationSelectorControl.CurrentItem;

                var allJobs = GetTimerJobsByName(Definitions.SearchNavigationSyncTimerJobName, _currentWebApp);
                if (allJobs == null) return;

                var searchCenterUrl = tbSearchSiteUrl.Text;
                var siteCollectionUrls = ConvertUrlsStringToArrayList(tbSiteCollectionsUrls.Text);
                var sitsToExcludeUrls = ConvertUrlsStringToArrayList(tbSitesToExcludeUrls.Text);

                //remove other orphaned jobs after the first one has been saved
                var jobUpdated = false;
                var spJobDefinitions = allJobs as SPJobDefinition[] ?? allJobs.ToArray();
                
                for (var i = spJobDefinitions.Length - 1; i >= 0; i--)
                {
                    var job = spJobDefinitions[i];
                    if (job is SearchNavigationSyncTimerJobDefinition)
                    {
                        if (!jobUpdated)
                        {
                            var searchNavSyncJob = job as SearchNavigationSyncTimerJobDefinition;

                            searchNavSyncJob.SearchCenterUrl = searchCenterUrl;
                            searchNavSyncJob.SiteCollectionsUrls = siteCollectionUrls;
                            searchNavSyncJob.AddThisSite = cbAddThisSite.Checked;
                            searchNavSyncJob.ExcludedSiteUrls = sitsToExcludeUrls;
                            searchNavSyncJob.MakeThisSiteFirst = cbThisSiteFirst.Checked;
                            searchNavSyncJob.SynchronizeAllSiteCollections = cbSyncAllSiteCollections.Checked;

                            searchNavSyncJob.Update();

                            OutputMessageToUser(
                                String.Format(
                                    "Settings have been applied to the {0} Timer Job.  You may navigate away from this page now.",
                                    Definitions.SearchNavigationSyncTimerJobTitle), System.Drawing.Color.Green);
                            jobUpdated = true;
                        }
                        else
                        {
                            job.Delete();
                        }
                    }
                }

                if (jobUpdated) return;

                OutputMessageToUser(
                    String.Format(
                        "Settings have NOT been applied successfully to the {0} Timer Job. Please Try Again.",
                        Definitions.SearchNavigationSyncTimerJobTitle), System.Drawing.Color.Red);
            }
            catch (Exception ex)
            {
                var errorMessage =
                    String.Format(
                        "An error occurred while saving the {0} Timer Job settings.  Please Try Again.<br/><br/>Error: {1}",
                        Definitions.SearchNavigationSyncTimerJobTitle, ex.Message);

                //log error and notify the end user
                UlsHelper.WriteUlsEntry(ex, TraceSeverity.Unexpected, EventSeverity.Error, Definitions.UlsCategory);
                OutputMessageToUser(errorMessage, System.Drawing.Color.Red);
            }
        }

        /// <summary>
        /// Converts the timer job's stored list of url's to a new line delimited string
        /// </summary>
        /// <param name="siteCollectionUrls">Collection of urls</param>
        /// <returns>Newline delimited string</returns>
        private static string ConvertUrlsArrayListToString(ArrayList siteCollectionUrls)
        {
            var retVal = "";
            if (siteCollectionUrls != null)
            {
                foreach (string val in siteCollectionUrls)
                {
                    if (!string.IsNullOrEmpty(retVal)) retVal += '\n';
                    retVal += val;
                }
            }
            return retVal;
        }

        /// <summary>
        /// Converts the new line delimited string to a list of url's
        /// </summary>
        /// <param name="siteCollectionUrls">New line delimited string of urls</param>
        /// <returns>Collection of urls</returns>
        private static ArrayList ConvertUrlsStringToArrayList(string siteCollectionUrls)
        {
            var retVal = new ArrayList();
            var arrValues = siteCollectionUrls.Split('\n');

            foreach (var val in arrValues)
            {
                if (!string.IsNullOrEmpty(val.Trim())) retVal.Add(val.Replace("\r", ""));
            }
            return retVal;
        }

        /// <summary>
        /// Method to output messages to the page for the user
        /// </summary>
        /// <param name="message">Message contents</param>
        /// <param name="messageColour">Text colour</param>
        private void OutputMessageToUser(String message, System.Drawing.Color messageColour)
        {
            lblStatus.Text = message;
            lblStatus.ForeColor = messageColour;
            ajaxUpMain.Update();
        }

        /// <summary>
        /// Method to get all instances of the Timer Job by Name
        /// </summary>
        /// <param name="internalName">The Internal Name of the Timer Job</param>
        /// <param name="webApp">SPWebApplication object for the currently selected web app</param>
        /// <returns>List of Timer Job Definitions</returns>
        private IEnumerable<SPJobDefinition> GetTimerJobsByName(string internalName, SPWebApplication webApp)
        {
            try
            {
                var allJobs = new List<SPJobDefinition>();
                allJobs.AddRange(from def in webApp.JobDefinitions
                                 where def.Name.ToLower() == internalName.ToLower()
                                 select def);

                return allJobs;
            }
            catch (Exception ex)
            {
                var errorMessage =
                    String.Format(
                        "An error occurred while retrieving the {0} Timer Job.  Please Try Again.<br/><br/>Error: {1}",
                        Definitions.SearchNavigationSyncTimerJobTitle, ex.Message);
                //log error and notify the end user
                UlsHelper.WriteUlsEntry(ex, TraceSeverity.Unexpected, EventSeverity.Error, Definitions.UlsCategory);
                OutputMessageToUser(errorMessage, System.Drawing.Color.Red);

                return null;
            }
        }
    }
}
